﻿using System;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Security.Permissions;
using JQuery.Net.Modules;
using System.Globalization;
using System.IO;
using JQuery.Net.Controls;

namespace JQuery.Net.UI
{
    public enum EnumClock
    {
        Standard = 12,
        Military = 24
    }

    [Flags]
    public enum EnumDateTimePicker
    {
        Both = EnumDateTimePicker.Date | EnumDateTimePicker.Time,
        Time = 1,
        Date = 2
    }

    [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
    [ToolboxData("<{0}:AnyTime runat=server></{0}:AnyTime>")]
    public class AnyTime 
        : jQNetControl
        , IPostBackDataHandler
    {
        #region Contructor
        public AnyTime()
            : base(HtmlTextWriterTag.Input)
        {
            Value = DateTime.FromOADate(2);

            Attributes["type"] = "text"; // this is a text input
        }
        #endregion

        private static readonly object change_key = new object();

        #region Properties
        private ResourceManager Manager { get; set; }
        /// <summary>
        /// Get or Set the Value of the AnyTime Picker
        /// </summary>
        public DateTime Value { get; set; }

        public String DateTimeFormatter
        {
            get
            {
                return GenerateFormatter(true);
            }
        }
        /// <summary>
        /// Get or Set Clock Format to Standard or Military Time.
        /// </summary>
        [Bindable(true), Category("Behavior"), Description("Display either a 12 or 24 hour clock.")]
        public EnumClock Clock { get; set; }
        /// <summary>
        /// Get or Set the Picker Type: Date, Time, or Both.
        /// </summary>
        [Bindable(true), Category("Behavior"), Description("Display Date, Time or DateTime Picker.")]
        public EnumDateTimePicker Picker { get; set; }
        /// <summary>
        /// Get or Set the Date Format used to render on the UI.
        /// </summary>
        [Bindable(true), Category("Appearance"), Description("Date Format I.E.: %m/%d/%Z"), DefaultValue("%m/%d/%Z")]
        public string DateFormat { get; set; }
        /// <summary>
        /// Get or Set the Time Format used to render on the UI.
        /// </summary>
        [Bindable(true), Category("Appearance"), Description("Time Format I.E.: %H:%i or %h:%i %p"), DefaultValue("")]
        public string TimeFormat { get; set; }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public override List<Script> ScriptEvents
        {
            get
            {
                return base.ScriptEvents;
            }
            set
            {
                base.ScriptEvents = value;
            }
        }
        #endregion

        #region events
        public event EventHandler DateTimeChanged
        {
            add { Events.AddHandler(change_key, value); }
            remove { Events.RemoveHandler(change_key, value); }
        }
        #endregion

        #region methods
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            Page.InitComplete += new EventHandler(Page_InitComplete);
        }

        void Page_InitComplete(object sender, EventArgs e)
        {
            if (!Page.IsCallback)
            {
                CSSRegistration.Registration(Manager.Resources[Resources.Css.ui_anytime]);
            }
        }

        public override void RegisterJQNScriptInclude(ResourceManager Manager, JQNRegistration Options)
        {
            this.Manager = Manager;

            if (Manager.IsResourceRegistered(Resources.JQN.ui_anytime) == false)
            {   /// Register the any time js script
                Manager.Add(Manager.Resources[Resources.JQN.ui_anytime]);
            }
        }

        public override void RegisterJQNScriptStartup(StringWriter writer)
        {
            var events = new StringBuilder();

            foreach (var key in Scripts.Keys)
            {
                events.AppendFormat("{0}: {1}{2}", key, Scripts[key], key == Scripts.Keys.Last() ? String.Empty : ",");
            }

            writer.WriteLine(String.Format("\t$('#{0}').AnyTime_picker({{ format: '{1}', {2} }})", ClientID, GenerateFormatter(false), events.ToString()));

#if DEBUG
            writer.WriteLine();
#endif
        }

        protected override bool ProcessPostData(NameValueCollection data)
        {
            DateTime __post_value;
            bool __IsChanged = false;

            if (DateTime.TryParse(data[UniqueID], out __post_value))
            {   /// the data posted back is a date time object
                if (__IsChanged = (__post_value > DateTime.FromOADate(2) && Value != __post_value))
                {   /// in this case the value has changed 
                    Value = __post_value;
                }
            }

            return __IsChanged;
        }

        public override void RaisePostDataChangedEvent()
        {   /// the text has changed we need to process the text changed event.
            var handler = (EventHandler)Events[change_key];

            if (Arguments != null)
            {
                Arguments.Cancel = handler == null;
            }

            if (handler != null)
            {
                handler(this, Page.IsCallback ? Arguments : new EventArgs());
            }
        }

        protected string GenerateFormatter(bool server)
        {
            StringBuilder oFormat = new StringBuilder();

            if ((Picker & EnumDateTimePicker.Date) != 0)
            {   /// Date Flag for the picker was set
                if (server)
                    oFormat.Append("MM/dd/yyyy");
                else
                    oFormat.Append(DateFormat);
            }

            if ((Picker & EnumDateTimePicker.Both) != 0)
            {   /// Both flags are set so add a space
                oFormat.Append(" ");
            }

            if ((Picker & EnumDateTimePicker.Time) != 0)
            {   /// Date Flag for the picker was set
                if (server)
                {
                    if (Clock == EnumClock.Military)
                        oFormat.Append("HH:mm");
                    else if (Clock == EnumClock.Standard)
                        oFormat.Append("hh:mm tt");
                }
                else
                {
                    if (TimeFormat.IsNullOrEmpty() && Clock == EnumClock.Military)
                        oFormat.Append("%H:%i");
                    else if (TimeFormat.IsNullOrEmpty() && Clock == EnumClock.Standard)
                        oFormat.Append("%h:%i %p");
                    else
                        oFormat.Append(TimeFormat);
                }
            }

            return oFormat.ToString();
        }
        #endregion

        protected override void RenderBeginTag(HtmlTextWriter writer)
        {
            /// if the value of the DateTime object has been updated set it here.
            if (Value > DateTime.FromOADate(2))
                Attributes["value"] = Value.ToString(DateTimeFormatter, DateTimeFormatInfo.InvariantInfo);

            base.RenderBeginTag(writer);
        }
    }
}
